<template>
  <a-spin :spinning="loading">
    <!-- 菜单、按钮的权限树形表格 -->
    <div class="TreeTable-container" id="TreeTable-container">
      <div class="t-table-head">
        <div
          class="t-table-td t-table-th"
          :style="{ width: column.width, flex: column.width ? 'none' : 'auto',borderRight: columns[index + 1] && !columns[index + 1].title && 'none',textAlign: columns[index + 1] && !columns[index + 1].title && 'right',marginRight: columns[index + 1] && !columns[index + 1].title && `-${column.title.length}rem`,zIndex: columns[index + 1] && !columns[index + 1].title && 99 }"
          v-for="(column,index) in columns"
          :key="column.dataIndex"
        >
          {{ column.title }}
        </div>
      </div>
      <div
        id="t-table-body"
        class="t-table-body"
        :style="{ 'max-height': height + 'px' }"
        v-show="dataSource && dataSource.length"
      >
        <div class="t-table-tr" v-for="row in dataSource" :key="row[rowKey]">
          <Node
            :columnsWidth="columnsWidth"
            :nodeData="row"
            :isRoot="true"
            @childChecked="handleChildChecked($event, row)"
            :showContent.sync="row.showContent"
            :maxDeep="columns.length"
          />
        </div>
      </div>
      <div class="t-table-body--empty" v-if="!dataSource || !dataSource.length">
        <a-empty />
      </div>
    </div>
  </a-spin>
</template>

<script>
import { clientId } from '@/config'
import { getAuthResource } from '@/api/system/system.js'
import { Empty } from 'ant-design-vue'
import Node from './node'
export default {
  name:'a'+Date.now(),
  components: {
    Node,
    AEmpty: Empty,
  },
  props: {
    rowKey: {
      type: String,
      default: 'id',
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    // 列配置项
    columns: {
      type: Array,
      default() {
        return [
          {
            title: '一级菜单',
            width: '250px'
          },
          {
            title: '二级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
          {
            title: '二级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
          {
            title: '三级菜单',
            width: '250px'
          },
        ]
      },
    },
    // 表格的body高度
    height: {
      type: Number,
      default: 600,
    },
    selectedKeys: {
      type: Array,
      default() {
        return []
      },
    },
    // 是否初始化选中
    selectedInitial: {
      type: Boolean,
      default: true,
    },
    userId: {
      type: String,
      default: '',
    },
    roleId: {
      type: String,
      default: '',
    },
    tabType: {
      type:String,
      default: '1'
    }
  },
  data() {
    return {
      loading: false,
      dataSource: [],
      updateLock: false, // 更新树节点选中状态时，上的锁
      showContent: true,
      columnsWidth: [], // 存储列宽
      isScroll: false, // 是否有滚动条的标识
      scrollWidth: 0, // 滚动条宽度
      isAdd: false
    }
  },
  watch: {
    selectedKeys: {
      handler(val) {
        if(!this.selectedInitial) {
          this.getAuthResourceReq()
        }
      },
    },
  },
  mounted() {
    if(this.$route.query.pageType) {
      if(this.$route.query.pageType == 'add') {
        this.isAdd = true
      } else {
        this.isAdd = false
      }
    }
    // this.initPageEvent()
    this.getAuthResourceReq()
  },
  methods: {
    /**
     * 计算表格body的是否有滚动，及滚动条宽度
     */
    calcBody() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          const dom = document.querySelector('#t-table-body')
          if (dom.scrollHeight > dom.clientHeight) {
            this.scrollWidth = dom.offsetWidth - dom.clientWidth
            this.isScroll = true
          } else {
            this.isScroll = false
          }
          resolve()
        }, 0)
      })
    },
    getSelectedList() {
      const selectedList = []
      const deepFn = (list) => {
        list &&
          list.forEach((item) => {
            // 筛选出选中状态,及半选状态的节点
            if (item.checked || item.indeterminate && !item.checked) {
              selectedList.push(item)
            }
            item.children && deepFn(item.children)
          })
      }
      deepFn(this.dataSource)
      return selectedList
    },
    async getAuthResourceReq() {
      if (this.loading) return
      this.loading = true
      const params = {
        userId: this.userId || void 0, // 用户ID
        role: this.roleId || void 0, // 角色ID
        clientId: clientId,
        resTypes: this.tabType === '1' ? '1,2,9' : '1,9', // 1：菜单  2：按钮  9：url
      }
      try {
        const res = await getAuthResource(params)
        let resultList = res.data
        console.log(resultList, 'yew')
        const idx = resultList.findIndex(item => item.data.resource.title === '项目管理' )
        const idx2 = resultList[idx].children.findIndex(item => item.data.resource.title === '业务查询' )
        if(this.tabType === '1') {
          resultList[idx].children.splice(idx2, 1)
          console.log(resultList, '操作')
        } else {
         const r = resultList[idx].children[idx2]
          console.log(r, '业务')
          resultList = [r];
        }
        // 遍历树，构建需要的数据结构
        const depFn = (list, deepth = 1) => {
          list &&
            list.forEach((item) => {
              item.name = item.data.resource.title
              if(this.isAdd&&this.tabType === '2') {
                item.checked = true
              } else {
                // selectedInitial为false时，则根据selectedKeys进行初始化选中
                if (!this.selectedInitial) {
                  item.checked = this.selectedKeys.includes(item[this.rowKey])
                } else {
                  item.checked = item.data.resource.authorized
                }
              }
              item.indeterminate = false
              item.showContent = false
              item.deepth = deepth
              item.disabled = this.disabled
              if (item.children) {
                depFn(item.children, deepth + 1)
              }
            })
        }
        depFn(resultList)
        // 重新更新节点的选中状态，避免传入的selectedKeys有误
        resultList.forEach((item) => {
          this.handleChildChecked({}, item)
        })
        this.dataSource = resultList
        this.$emit("loadFinish", this.tabType)
        this.$nextTick(() => {
          this.initWidth()
        })
      } catch (e) {
        console.error(e)
      } finally {
        this.loading = false
      }
    },
    /**
     * 监听窗口大小变动事件，重新计算列宽
     */
    initPageEvent() {
      const handler = () => {
        this.initWidth.call(this)
      }
      handler() // 执行一次，初始化宽度
      window.addEventListener('resize', handler)
      this.$once('hook:beforeDestroy', () => {
        window.removeEventListener('resize', handler)
      })
    },
    /**
     * 计算列宽
     */
    initWidth() {
      try {
        const thDoms = document.getElementsByClassName('t-table-th')
        const thList = Array.from(thDoms)
        this.columnsWidth = []
        thList.forEach((item) => {
          this.columnsWidth.push(window.getComputedStyle(item).width)
        })
        this.calcBody().then(() => {
          if (this.isScroll) {
            const lastColumn = this.columnsWidth[this.columnsWidth.length - 1].split('px')[0]
            this.$set(this.columnsWidth, this.columnsWidth.length - 1, lastColumn - this.scrollWidth + 'px')
          }
        }).catch((e) => {
          console.error(e)
        })
      } catch (e) {
        console.error(e)
      }
    },
    /**
     * 更新子级的状态
     * @param {object} nodeData 节点数据
     */
    updateChildNode(nodeData) {
      const { checked } = nodeData
      nodeData.children &&
        nodeData.children.forEach((item) => {
          item.checked = checked
          item.indeterminate = false
          // 递归更新子级
          this.updateChildNode(item)
        })
    },
    /**
     * 更新当前节点的状态
     * @param {object} nodeData 节点数据
     */
    updateNode(nodeData) {
      if (!nodeData.children || !nodeData.children.length) return
      // 筛选出选中的子项
      const childSelectedList = (nodeData.children && nodeData.children.filter((item) => item.checked)) || []
      const len = childSelectedList.length
      nodeData.checked = len > 0 && len === nodeData.children.length
      // 包括子级有半选状态时，也要将当前节点置为半选
      nodeData.indeterminate =
        (len > 0 && len < nodeData.children.length) ||
        (nodeData.children && nodeData.children.some((item) => item.indeterminate))
    },
    /**
     * 处理子节点的check事件，更新树其他节点选中状态
     * 更新路径为，从触发节点开始向叶子节点更新，再从叶子节点回到根节点进行更新，从而更新整棵树的状态
     * @param {Object} targetNode 触发check事件的节点
     * @param {Object} data 树结构的根节点
     */
    handleChildChecked(targetNode, data) {
      if (this.updateLock) return
      this.updateLock = true // 在遍历时，设置更新锁，防止反复触发
      const targetId = targetNode[this.rowKey]
      let queue = []
      queue.push(data) // 通过广度优先遍历，生成节点的队列树
      let allowUpdateChild = false
      for (let i = 0; i < queue.length; i++) {
        const targetData = queue[i]
        // 找到触发节点的位置
        if (targetData[this.rowKey] === targetId) {
          allowUpdateChild = true
        }
        // 更新触发节点子级的选中状态
        if (allowUpdateChild) {
          this.updateChildNode(targetData)
          // 更新完子级之后，需要将allowUpdateChild置为false，否则会在下一次循环中导致其他非目标节点也去更新自己的子级
          allowUpdateChild = false
        }
        if (targetData.children && targetData.children.length) {
          queue = queue.concat(targetData.children)
        }
      }
      // 根据第一次遍历得到的队列，依次从叶子节点回到根节点，这个过程中更新每一个节点的选中状态
      for (let j = queue.length - 1; j >= 0; j--) {
        const targetData = queue[j]
        this.updateNode(targetData)
      }
      this.updateLock = false
    },
  },
}
</script>

<style lang="less" scoped>
@borer-color: #e8e8e8;
.TreeTable-container {
  border-top: 1px solid @borer-color;
  border-left: 1px solid @borer-color;
  .t-table-td {
    border-right: 1px solid @borer-color;
    border-bottom: 1px solid @borer-color;
    text-align: center;
  }
  .t-table-head {
    display: flex;
    visibility: hidden;
    height: 0;
    overflow: hidden;
    .t-table-th {
      flex: auto;
      padding: 10px 20px;
      box-sizing: border-box;
      background: #fafafa;
      font-weight: 500;
      color: #000000;
    }
  }
  .t-table-body {
    overflow: auto;
    scrollbar-width: none;
    // &::-webkit-scrollbar {
    //   display: none; /* Chrome Safari */
    // }
    // -ms-overflow-style: none; /* IE 10+ */
    // scrollbar-width: none; /* Firefox */
    .t-table-tr {
      display: flex;
    }
  }
  .t-table-body--empty {
    height: 400px;
    border-right: 1px solid @borer-color;
    border-bottom: 1px solid @borer-color;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>
